package com.lyd.sweet.feign.decoder;

import com.lyd.sweet.model.ResponseObject;
import feign.FeignException;
import feign.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringDecoder;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map;

/**
 * feign响应结果解析器
 * @author 木木
 */
@Slf4j
public class FeignSuccessDecoder extends SpringDecoder {

    public FeignSuccessDecoder(ObjectFactory<HttpMessageConverters> messageConverters) {
        super(messageConverters);
    }

    /**
     * 使用sweet boot开发的服务间使用Feign调用时,根据feignClient定义的接口ReturnType将响应结果解析为对应的对象
     * {@link ResponseObject}
     *
     * @param response Feign响应
     * @param type     {@link Type}
     * @return {@link Type} result
     * @throws IOException
     * @throws FeignException
     */
    @Override
    public Object decode(Response response, Type type) throws IOException, FeignException {
        log.debug("FeignSuccessDecoder.decode.param.typeName:{}", type.getTypeName());
        boolean isReturnResponseObjectType = type.getTypeName().startsWith(ResponseObject.class.getTypeName());

        Map<String, Collection<String>> resHeaders = response.headers();
        Collection<String> resIsResponseObjects = resHeaders.get("IsResponseObject");
        String isResponseObjectStr = resIsResponseObjects.stream().findFirst().orElse("false");
        boolean isResponseObject = "true".equals(isResponseObjectStr);

        //方法返回类型为ResponseObject
        if (isReturnResponseObjectType) {
            //结果非ResponseObject
            if (!isResponseObject) {
                Object value = super.decode(response, Object.class);
                return ResponseObject.success(value);
            }

            return super.decode(response, type);
        }

        //结果为ResponseObject，方法返回类型非ResponseObject
        if (isResponseObject) {
            ResponseObject<?> result = (ResponseObject<?>) super.decode(response, new ResponseObjectParameterizedType(new Type[]{type}));
            //只返回data
            return result.getData();
        }

        //结果非ResponseObject，方法返回类型非ResponseObject
        return super.decode(response, type);
    }

    /**
     * 定义一个ResponseObject结构类型
     * {@link ResponseObject}
     */
    static final class ResponseObjectParameterizedType implements ParameterizedType {
        private final Type[] actualTypeArguments;

        ResponseObjectParameterizedType(Type[] actualTypeArguments) {
            this.actualTypeArguments = actualTypeArguments;
        }

        public Type[] getActualTypeArguments() {
            return this.actualTypeArguments;
        }

        public Type getRawType() {
            return ResponseObject.class;
        }

        public Type getOwnerType() {
            return null;
        }
    }
}
